/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.commands.association;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.UMLFactory;

import com.cea.papyrus.core.IPapyrusUIConstants;
import com.cea.papyrus.core.commands.connection.ConnectionCreateCommand;
import com.cea.papyrus.core.helper.IModelerHelper;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.utils.VectorCalculus;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Command to create a new association edge.
 */
public class AssociationCreateCommand extends ConnectionCreateCommand {

	/**
	 * created association.
	 */
	protected Association association = null;
	
	/**
	 * target property.
	 */
	protected Property targetProperty = null;
	
	/**
	 * source property.
	 */
	protected Property sourceProperty = null;
	
	/**
	 * Creates a new AssociationCreateCommand.
	 * 
	 * @param type the type of umlElement to be created
	 * @param location  Point where the source is dropped
	 * @param source the source Graph Element for the link representing the association
	 */
	public AssociationCreateCommand(GraphElement source, Object type, Point location) {
		super(source, type, location);
	}

	/**
	 * Creates the bussiness model.
	 * The created model should be stored by the implementation class for future use (in reconnect/disconnect)
	 * 
	 * @return The created object.
	 */
	@Override
	public Element createBussinessModel() {
		final Classifier umlTarget;
		// !! warning : the edge is still not created
		//connect the graphEdge to the diagram and UML Elements
		final Classifier umlSource = (Classifier)getSourceElement();
		Element e=getTargetElement();
		if (e instanceof Classifier){
			umlTarget= (Classifier)getTargetElement();
		}
		else{
			umlTarget= (Classifier)((ElementImport)getTargetElement()).getImportedElement();
		}

		//((Notifier)getSource()).eAdapters().clear();
		//((Notifier)getTarget()).eAdapters().clear();
		//((Notifier)getOwner()).eAdapters().clear();

		association = (Association)ModelerHelper.getFactory().createUMLElement(Association.class, getUMLParent());
		com.cea.papyrus.umlutils.Association utilsAssocation = new com.cea.papyrus.umlutils.Association(association);
		// get property names
		String name = utilsAssocation.getPropertyNameFromType(umlTarget);
		
		// create 1st property
		targetProperty = (Property)getClassDiagramModelerHelper().createUMLElement(Property.class, name, umlSource);
		targetProperty.setAggregation(AggregationKind.NONE_LITERAL);
		targetProperty.setType(umlTarget);
		LiteralInteger theint= UMLFactory.eINSTANCE.createLiteralInteger();
		theint.setValue(0);
		targetProperty.setLowerValue(theint);
		LiteralUnlimitedNatural thenatural=UMLFactory.eINSTANCE.createLiteralUnlimitedNatural();
		thenatural.setValue(-1);
		targetProperty.setUpperValue(thenatural);
		
		
		name = utilsAssocation.getPropertyNameFromType(umlSource);
		// create 2nd property
		sourceProperty = (Property)getClassDiagramModelerHelper().createUMLElement(Property.class, name, association);
		sourceProperty.setType(umlSource);
		sourceProperty.setAggregation(AggregationKind.NONE_LITERAL);
		thenatural =UMLFactory.eINSTANCE.createLiteralUnlimitedNatural();
		thenatural.setValue(-1);
		sourceProperty.setUpperValue(thenatural);
		theint= UMLFactory.eINSTANCE.createLiteralInteger();
		theint.setValue(0);
		sourceProperty.setLowerValue(theint);
		
		//connect UML element
		ModelerHelper.getFactory().connect(Association.class, sourceProperty, targetProperty, association);
		
		// Return the created bussiness element. It is stored inside the GraphEdge.
		return association;
	}

    /**
     * Return the ClassDiagram modelerHelper
     * @TODO Remove this kind of references to another plugin !
     * This command should be independant from any diagram. The implementation inside this method 
     * looks like a dependance on classdiagram !
     */
    private IModelerHelper getClassDiagramModelerHelper() {
        return ModelerHelper.getFactory(IPapyrusUIConstants.CLASS_DIAGRAM);
    }
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.commands.ConnectionCreateCommand#createGraphEdge(org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param umlLink 
	 * 
	 * @return 
	 */
	@Override
	protected GraphEdge createGraphEdge(Element umlLink) {
		GraphEdge edge = super.createGraphEdge(umlLink);
		if ((getSource() instanceof GraphNode) && (getTarget() instanceof GraphNode)){
			VectorCalculus.setGoodPositionForAssociation(edge, ((GraphNode)getSource()), ((GraphNode)getTarget()));
			}
		return edge;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.commands.ConnectionCreateCommand#disconnectBussinessModel(com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge)
	 */
	/**
	 * 
	 * 
	 * @param bridge 
	 * @param targetBridge 
	 * @param sourceBridge 
	 */
	@Override
	public void disconnectBussinessModel(Uml1SemanticModelBridge bridge, Uml1SemanticModelBridge sourceBridge, Uml1SemanticModelBridge targetBridge) {
		// deconnect association from its end properties
		ModelerHelper.getFactory().deconnect(Association.class, sourceProperty, targetProperty, association);
		
		//remove properties
		getClassDiagramModelerHelper().removeElement(Property.class, sourceProperty, sourceProperty.getOwner());
		getClassDiagramModelerHelper().removeElement(Property.class, targetProperty, targetProperty.getOwner());
		
		// remove association
		ModelerHelper.getFactory().removeElement(Association.class, association, getUMLParent());
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.commands.ConnectionCreateCommand#reconnectBussinessModel(com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge, com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge)
	 */
	/**
	 * 
	 * 
	 * @param bridge 
	 * @param targetBridge 
	 * @param sourceBridge 
	 */
	@Override
	public void reconnectBussinessModel(Uml1SemanticModelBridge bridge, Uml1SemanticModelBridge sourceBridge, Uml1SemanticModelBridge targetBridge) {
		// add association
		ModelerHelper.getFactory().addUMLElement(Association.class, association, getUMLParent());
		
		getClassDiagramModelerHelper().addUMLElement(Property.class, targetProperty, getSourceElement());
		getClassDiagramModelerHelper().addUMLElement(Property.class, sourceProperty, association);
		
		// connect association
		ModelerHelper.getFactory().connect(Association.class, sourceProperty, targetProperty, association);
	}
}
